孤舟蓑笠翁,独钓寒江雪

Android 组件 -- ActivityGroup 简介

ActivityGroup简介

ActivityGroup可以看作是Activity的容器,可以包含多个嵌套进来的Activity
我们只需要知道有这个类就可以了,现在这个类现在已经不推荐使用了,是deprecated状态的,一般情况下是可以被Fragment取代的,但是在一些特殊场合下仍然是被需要的。
下面通过一个Demo来介绍ActivityGroup的使用。

示例

代码

MainActivity.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
public class MainActivity extends ActivityGroup {

private ViewGroup mLeft;
private ViewGroup mRight;
private LocalActivityManager manager;
private View mRoot;
private static WeakReference<MainActivity> mInstance;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
mInstance = new WeakReference<MainActivity>(this);
setContentView(R.layout.activity_main);
manager = getLocalActivityManager();
mRoot = findViewById(R.id.container_main);
mLeft = (ViewGroup) findViewById(R.id.container_left);
mRight = (ViewGroup) findViewById(R.id.container_right);

startLeftActivity();
}

public static MainActivity getInstance(){
return mInstance != null ? mInstance.get() : null;
}

public void startLeftActivity(){
mLeft.removeAllViews();
Intent i = new Intent(this, LeftActivity.class);
mLeft.addView(manager.startActivity("LeftActivity", i).getDecorView());
}

public void startRightActivity(){
mRight.removeAllViews();
Intent i = new Intent(this, RightActivity.class);
mRight.addView(manager.startActivity("RightActivity", i).getDecorView());
}
}

activity_main.xml

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout
android:id="@+id/container_main"
xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="horizontal"
android:showDividers="middle"
android:divider="?android:attr/dividerHorizontal"
tools:context="com.android.hq.testapplication.MainActivity">

<FrameLayout
android:id="@+id/container_left"
android:layout_width="150dp"
android:layout_height="match_parent"
android:layout_weight="0">

</FrameLayout>

<FrameLayout
android:id="@+id/container_right"
android:layout_width="0dp"
android:layout_height="match_parent"
android:layout_weight="1">
<TextView
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:text="Empty"/>
</FrameLayout>
</LinearLayout>

LeftActivity.java

1
2
3
4
5
6
7
8
9
10
11
public class LeftActivity extends Activity{
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_left);
}

public void startRightActivity(View v){
MainActivity.getInstance().startRightActivity();
}
}

效果

在启动右边的Activity之前,右边区域是空的:

点击按钮启动右边Activity

源码分析

从源码中我们可以看到ActivityGroup类的父类是Activity,也就是说二者具有相同的方法和生命周期。在ActivityGroup有成员变量protected LocalActivityManager mLocalActivityManager,那么ActivityGroupActivity的管理就要以来这个变量来管理了。
ActivityGrouponCreate`onResumeonPause`等生命周期函数里面分别调用

1
2
3
Bundle states = savedInstanceState != null
? (Bundle) savedInstanceState.getBundle(STATES_KEY) : null;
mLocalActivityManager.dispatchCreate(states);

1
mLocalActivityManager.dispatchResume();
1
mLocalActivityManager.dispatchPause(isFinishing());

来保证子Activity的生命周期与ActivityGroup一致。
LocalActivityManager通过startActivity(String id,Intent intent)这个方法获取当前Window对象,再然后调用getDecorView()方法获取当前Activity对应的View,这个就把多个Activity添加到一个RootView里面了。
具体是怎么获得我们需要ActivityDecorView的呢?我们就要看一下LocalActivityManagerstartActivity这个方法了。
首先要获取主线程的mActivityThread

1
mActivityThread = ActivityThread.currentActivityThread();

1
2
3
4
5
6
r.activity = mActivityThread.startActivityNow(
mParent, r.id, r.intent, r.activityInfo, r, r.instanceState, instance);
if (r.activity == null) {
return;
}
r.window = r.activity.getWindow();

这里调用了mActivityThread.startActivityNow方法,在startActivityNow内部会调用ActivityThread.performLaunchActivity来装载这个Activity,然后通过activity.getWindow()获得Window对象,在通过Window获得DecorView